package subpub

import (
	"fmt"
	"gitee.com/ymofen/gobase"
	"sync"
)

type SubSessionIntf interface {
	Start()
	Close() error
	PostData(args ...interface{}) error
}

// 订阅中心
// 负责创建管理会话对象
// 注册的方法必须是sub.开头
type SubHub struct {
	notify      *Subchannel
	defaulttype string
	lk          sync.RWMutex
	lstMap      map[string]interface{}
}

var (
	DefaultSub = NewSubHub()
)

func NewSubHub() *SubHub {
	rval := &SubHub{
		lstMap: make(map[string]interface{}),
		notify: NewSubchannel(),
	}
	return rval
}

func (this *SubHub) ConfigDefaultConnType(s string) {
	this.defaulttype = s
}

func (this *SubHub) Status() string {
	return this.notify.Status()
}

func (this *SubHub) AddSession(sessionid string, conf gobase.StrMap, fn SubFunc) error {
	this.lk.RLock()
	obj := this.lstMap[sessionid]
	this.lk.RUnlock()
	if obj != nil {
		return fmt.Errorf("[%s]已经存在", sessionid)
	}

	typestr := conf.StringByName("conntype", "")
	if len(typestr) == 0 {
		if len(this.defaulttype) > 0 {
			typestr = fmt.Sprintf("sub.%s", this.defaulttype)
		} else {
			return fmt.Errorf("未指定conntype")
		}
	} else {
		typestr = fmt.Sprintf("sub.%s", typestr)
	}
	obj, err := gobase.CreateFactoryInstance(typestr, sessionid, conf, this.notify)
	if err != nil {
		return err
	}
	intf, ok := obj.(SubSessionIntf)
	if !ok {
		return fmt.Errorf("[%s]类型插件不支持SubSessionIntf接口", typestr)
	}
	this.lk.Lock()
	this.lstMap[sessionid] = obj
	this.lk.Unlock()
	this.notify.Sub(sessionid, sessionid, fn)
	intf.Start()
	return nil
}

func (this *SubHub) DelSession(sessionid string) bool {
	this.lk.RLock()
	obj := this.lstMap[sessionid]
	this.lk.RUnlock()
	if obj != nil {
		if intf, ok := obj.(SubSessionIntf); ok {
			intf.Close()
		}
		this.lk.Lock()
		delete(this.lstMap, sessionid)
		this.lk.Unlock()
	}
	return this.notify.Unsub(sessionid, sessionid)
}

func (this *SubHub) PostData(sessionid string, args ...interface{}) error {
	this.lk.RLock()
	obj := this.lstMap[sessionid]
	this.lk.RUnlock()

	if obj == nil {
		return fmt.Errorf("%s不存在", sessionid)
	}

	if intf, ok := obj.(SubSessionIntf); ok {
		return intf.PostData(args...)
	} else {
		return fmt.Errorf("[%p]类型插件不支持SubSessionIntf接口", obj)
	}
}
